package com.tqz.rc.client.naming;

import com.tqz.rc.api.Instance;
import com.tqz.rc.api.ServiceInfo;
import com.tqz.rc.client.naming.cache.ServiceInfoHolder;
import com.tqz.rc.common.constant.DefaultValueConstant;
import com.tqz.rc.common.exception.RcException;
import com.tqz.rc.common.util.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

/**
 * <p>
 *
 * @author tianqingzhao
 * @since 2021/8/30 10:37
 */
public class NacosNamingService implements NamingService {

    private NamingClientProxy clientProxy;

    private ServiceInfoHolder serviceInfoHolder;

    public NacosNamingService(Properties properties) {
        init(properties);
    }

    private void init(Properties properties) {
        this.serviceInfoHolder = new ServiceInfoHolder();
        this.clientProxy = new NamingHttpClientProxy(serviceInfoHolder, properties);
    }

    @Override
    public void registerInstance(String serviceName, String ip, int port) throws RcException {
        registerInstance(serviceName, DefaultValueConstant.DEFAULT_GROUP, ip, port);
    }

    @Override
    public void registerInstance(String serviceName, String groupName, String ip, int port) throws RcException {
        registerInstance(serviceName, DefaultValueConstant.DEFAULT_CLUSTER_NAME, groupName, ip, port);
    }

    @Override
    public void registerInstance(String serviceName, String clusterName, String groupName, String ip, int port) throws RcException {
        registerInstance(DefaultValueConstant.DEFAULT_NAMESPACE_ID, serviceName, clusterName, groupName, ip, port);
    }

    @Override
    public void registerInstance(String namespaceId, String serviceName, String clusterName, String groupName, String ip, int port) throws RcException {
        Instance instance = new Instance();
        instance.setNamespaceId(namespaceId);
        instance.setServiceName(serviceName);
        instance.setClusterName(clusterName);
        instance.setIp(ip);
        instance.setPort(port);

        registerInstance(serviceName, groupName, instance);
    }

    @Override
    public void registerInstance(String serviceName, String groupName, Instance instance) throws RcException {
        clientProxy.registerInstance(serviceName, groupName, instance);
    }

    @Override
    public List<Instance> selectInstances(String serviceName) throws RcException {
        return selectInstances(serviceName, DefaultValueConstant.DEFAULT_GROUP);
    }

    @Override
    public List<Instance> selectInstances(String serviceName, String groupName) throws RcException {
        return selectInstances(serviceName, groupName, new ArrayList<>());
    }

    @Override
    public List<Instance> selectInstances(String serviceName, List<String> clusters) throws RcException {
        return selectInstances(serviceName, DefaultValueConstant.DEFAULT_GROUP, clusters);
    }

    @Override
    public List<Instance> selectInstances(String serviceName, String groupName, List<String> clusters) throws RcException {
        String clusterString = StringUtils.join(clusters, ",");
        ServiceInfo serviceInfo = serviceInfoHolder.getServiceInfo(serviceName, groupName, clusterString);
        List<Instance> instanceList = selectInstances(serviceInfo, true);
        return instanceList;
    }

    @Override
    public Instance selectOneHealthyInstance(String serviceName) throws RcException {
        return selectOneHealthyInstance(serviceName, DefaultValueConstant.DEFAULT_GROUP);
    }

    @Override
    public Instance selectOneHealthyInstance(String serviceName, String groupName) throws RcException {
        return selectOneHealthyInstance(serviceName, groupName, new ArrayList<String>());
    }

    @Override
    public Instance selectOneHealthyInstance(String serviceName, List<String> clusters) throws RcException {
        return selectOneHealthyInstance(serviceName, DefaultValueConstant.DEFAULT_GROUP, clusters);
    }

    @Override
    public Instance selectOneHealthyInstance(String serviceName, String groupName, List<String> clusters) throws RcException {
        String clusterString = StringUtils.join(clusters, ",");

        return Balancer.RandomByWeight.selectHost(serviceInfoHolder
                .getServiceInfo(serviceName, groupName, clusterString));
    }

    @Override
    public void shutdown() {
        serviceInfoHolder.shutdown();
        clientProxy.shutdown();
    }

    private List<Instance> selectInstances(ServiceInfo serviceInfo, boolean healthy) throws RcException {
        List<Instance> list;
        if (serviceInfo == null || CollectionUtils.isEmpty(list = serviceInfo.getHosts())) {
            return new ArrayList<Instance>();
        }

        Iterator<Instance> iterator = list.iterator();
        while (iterator.hasNext()) {
            Instance instance = iterator.next();
            if (healthy != instance.isHealthy() || instance.getWeight() <= 0) {
                iterator.remove();
            }
        }

        return list;
    }
}
